#include "canvas.h"
#include "point.h"
#include "line.h"
#include <QDebug>

Canvas::Canvas(const QString &imgName,
               const QPoint &leftTop,
               const QPoint &rightBottom,
               QGraphicsScene *scene,
               QGraphicsItem *parent) :
    ImageItem(imgName, leftTop, rightBottom, scene, parent) ,
    state(commons::DEFAULT)
{
    this->setAcceptHoverEvents(true);
    this->setEnabled(true);
    posBanner = new QGraphicsTextItem(this, scene);
    posBanner->setPos(60, -20);
    nameBanner = new QGraphicsTextItem(this, scene);
    nameBanner->setFont(QFont("Janis", 22));
    nameBanner->setDefaultTextColor(Qt::green);
    nameBanner->setPos(215, -30);
    nameBanner->setPlainText("[untitled]");
}

void Canvas::clear()
{
    while (!pointsList.isEmpty()) {
        Point* p = pointsList.first();
        pointsList.removeFirst();
        delete p;
    }
    while (!linesList.isEmpty()) {
        Line* l = linesList.first();
        linesList.removeFirst();
        delete l;
    }
    update();
}

void Canvas::copyGraph(const QLinkedList<Point *> &pl,
                       const QLinkedList<Line *> &ll)
{
    clear();

    QHash<Point*, Point*> convertMap;

    QLinkedList<Point *>::const_iterator pit;
    for (pit=pl.begin(); pit!=pl.end(); pit++) {
        Point* p = new Point(*(*pit));
        convertMap[*pit] = p;
        initEventSystem(p);
        p->setParentItem(this);
//        scene()->addItem(p);
        pointsList.push_back(p);
    }

    QLinkedList<Line *>::const_iterator lit;
    for (lit=ll.begin(); lit!=ll.end(); lit++) {
        Line* l = new Line(*(*lit));
        l->setStartPoint(convertMap[(*lit)->getStartPoint()]);
        if ((*lit)->getEndPoint() != NULL)
            l->setEndPoint(convertMap[(*lit)->getEndPoint()]);
        initEventSystem(l);
        l->setParentItem(this);
//        scene()->addItem(l);
        linesList.push_back(l);
    }
    update();
}

void Canvas::setNameBanner(const QString &name)
{
    nameBanner->setPlainText(name);
}

void Canvas::setState(CanvasState state)
{
    // qDebug()<<"canvas "<<state;
    this->state = state;
    QLinkedList<Point *>::iterator it;
    for (it=pointsList.begin(); it!=pointsList.end(); it++) {
        (*it)->setState(state);
    }
    QLinkedList<Line *>::iterator itp;
    for (itp=linesList.begin(); itp!=linesList.end(); itp++) {
        (*itp)->setState(state);
        if (state == commons::SOLVED)
            (*itp)->setColor(Qt::green);
    }
}

bool Canvas::isNearPoints(const QPointF &p1, const QPointF &p2) const
{
    static int gap = 8;
    qreal dx = p1.x() > p2.x() ? p1.x() - p2.x() : p2.x() - p1.x();
    qreal dy = p1.y() > p2.y() ? p1.y() - p2.y() : p2.y() - p1.y();
    return (dx<gap) && (dy<gap);
}

Point *Canvas::findNearbyPoint(const QPointF &pos)
{
    QLinkedList<Point *>::iterator it;
    for (it=pointsList.begin(); it!=pointsList.end(); it++) {
        if (isNearPoints(pos, (*it)->rect().center()))
            return (*it);
    }
    return NULL;
}

void Canvas::initEventSystem(Point *p)
{
    connect(p, SIGNAL(hoverEntered()), this, SLOT(aPointHasHoverEnter()));
    connect(p, SIGNAL(hoverLeft()), this, SLOT(aPointHasHoverLeave()));
    connect(p, SIGNAL(dragStart()), this, SLOT(aPointHasDragStart()));
    connect(p, SIGNAL(dragStop()), this, SLOT(aPointHasDragStop()));
    connect(p, SIGNAL(linerStart(Point*)), this, SLOT(aPointHasLinerStart(Point*)));
    connect(p, SIGNAL(pointMoved(Point*)), this, SLOT(aPointHasMove(Point*)));
    connect(p, SIGNAL(deletePoint(Point*)), this, SLOT(aPointNeedDelete(Point*)));
}

void Canvas::initEventSystem(Line *l)
{
    connect(l, SIGNAL(hoverEntered()), this, SLOT(aLineHasHoverEnter()));
    connect(l, SIGNAL(hoverLeft()), this, SLOT(aLineHasHoverLeave()));
    connect(l, SIGNAL(dragStart(Line*)), this, SLOT(aLineHasDragStart(Line*)));
    connect(l, SIGNAL(dragStop(Line*)), this, SLOT(aLineHasDragStop(Line*)));
    connect(l, SIGNAL(lineMoved(Line*)), this, SLOT(aLineHasMove(Line*)));
    connect(l, SIGNAL(deleteLine(Line*)), this, SLOT(aLineNeedDelete(Line*)));
}

void Canvas::paint(QPainter *painter, const QStyleOptionGraphicsItem *option, QWidget *widget)
{

}

void Canvas::hoverEnterEvent(QGraphicsSceneHoverEvent *event)
{
    emit canvasHoverEnter(state);
}

void Canvas::hoverLeaveEvent(QGraphicsSceneHoverEvent *event)
{
    emit canvasHoverLeave();
}

void Canvas::hoverMoveEvent(QGraphicsSceneHoverEvent *event)
{
    posBanner->setPlainText(QString().setNum(int(event->pos().x())) + ", " +
                            QString().setNum(int(event->pos().y())));
}

void Canvas::mousePressEvent(QGraphicsSceneMouseEvent *event)
{
    qDebug() << "can dow " << event->pos();
}

void Canvas::mouseReleaseEvent(QGraphicsSceneMouseEvent *event)
{
    if (state == commons::POINT) {
        Point *p = new Point(event->pos().toPoint(), this, scene());
        p->setState(state);
        initEventSystem(p);
        pointsList.push_back(p);
        update();
    } else if (state == commons::LINE_DRAWING) {
//        qDebug() << "drw lin stop";
        Point *nearbyPoint = findNearbyPoint(event->pos());
        if (nearbyPoint!=NULL)
            current->setDestnation(nearbyPoint);
        setState(commons::LINE);
        emit lineringStop();
    }
}

void Canvas::mouseMoveEvent(QGraphicsSceneMouseEvent *event)
{
    qDebug() << "mov " << event->pos();
    if (state == commons::LINE_DRAWING)
    {
        qDebug() << "linering" << event->pos();
        Point* nearbyPoint = findNearbyPoint(event->pos());
        if (nearbyPoint == NULL)
            current->setDestnation(event->pos().toPoint());
        else
            current->setDestnation(nearbyPoint->rect().center().toPoint());
    }
//    else if (state == commons::LINE_MOVING)
//    {
//        QPointF delta = event->pos() - lineMovingStart;
//        qDebug() << "line moving " << delta;
//        QLineF line = current->line();
//        line.p1() += delta;
//        line.p2() += delta;
//        current->setLine(line);
//        update();
//    }
}

void Canvas::aPointHasHoverEnter()
{
    if (state == commons::POINT || state == commons::PLAYING)
        emit pointHoverEnter();
    else if (state == commons::LINE)
        emit linerHoverEnter();
}

void Canvas::aPointHasHoverLeave()
{
    if (state == commons::POINT || state == commons::PLAYING)
        emit pointHoverLeave();
    else if (state == commons::LINE)
        emit linerHoverLeave();
}

void Canvas::aPointHasDragStart()
{
    if (state == commons::POINT || state == commons::PLAYING) {
        emit pointDragStart();
        prevState = state;
        setState(commons::POINT_MOVING);
    }
}

void Canvas::aPointHasDragStop()
{
    if (state == commons::POINT_MOVING) {
        emit pointDragStop();
        setState(prevState);
    }
}

void Canvas::aLineHasHoverEnter()
{
    if (state == commons::LINE || state == commons::PLAYING)
        emit lineHoverEnter();
}

void Canvas::aLineHasHoverLeave()
{
    if (state == commons::LINE || state == commons::PLAYING)
        emit lineHoverLeave();
}

void Canvas::aLineHasDragStart(Line* line)
{
    current = line;
    if (state == commons::LINE || state == commons::PLAYING) {
        emit lineDragStart();
        prevState = state;
        setState(commons::LINE_MOVING);
    }
}

void Canvas::aLineHasDragStop(Line* line)
{
    current = line;
    if (state == commons::LINE_MOVING) {
        emit lineDragStop();
        setState(prevState);
    }
}

void Canvas::aPointHasLinerStart(Point *point)
{
    current = new Line(point, this, scene());
    initEventSystem(current);
    linesList.push_back(current);
    setState(commons::LINE_DRAWING);
}

void Canvas::aPointHasMove(Point *point)
{
    QLinkedList<Line *>::iterator it;
    for (it=linesList.begin(); it!=linesList.end(); it++) {
        (*it)->update();
    }
}

void Canvas::aLineHasMove(Line *line)
{
    aPointHasMove(line->getStartPoint());
    if (line->getEndPoint()!=NULL)
        aPointHasMove(line->getEndPoint());
}

void Canvas::aPointNeedDelete(Point *point)
{

    detatchPoint(point);
    pointsList.removeOne(point);
    delete point;
    emit pointHoverLeave();

//    QLinkedList<Point *>::iterator it;
//    for (it=pointsList.begin(); it!=pointsList.end(); it++) {
//        if (point == (*it)) {
//        }
//    }
}

void Canvas::aLineNeedDelete(Line *line)
{
    linesList.removeOne(line);
    delete line;
    emit lineHoverLeave();

//    QLinkedList<Line *>::iterator it;
//    for (it=linesList.begin(); it!=linesList.end(); it++) {
//        if (line == (*it)) {
//        }
//    }
}

void Canvas::detatchPoint(Point *point)
{

    QLinkedList<Line *>::iterator it;
    for (it=linesList.begin(); it!=linesList.end(); it++) {
        Line* l = *it;
        if (l->getStartPoint() == point)
            l->detatchStartPoint();
        else if (l->getEndPoint() == point)
            l->detatchEndPoint();

        l->update();
    }
}




